﻿
Imports System.Threading
Imports osi.root.connector
Imports osi.root.lock
Imports osi.root.template
Imports osi.root.utils

Public Class sync_lazier(Of T, THREAD_SAFE As _boolean)
    Private Shared ReadOnly threadsafe As Boolean

    Shared Sub New()
        threadsafe = +alloc(Of THREAD_SAFE)()
    End Sub

    Private ReadOnly ts As sync_thread_safe_lazier(Of T)
    Private ReadOnly tus As sync_thread_unsafe_lazier(Of T)

    Public Sub New(ByVal d As Func(Of T))
        If threadsafe Then
            ts = New sync_thread_safe_lazier(Of T)(d)
        Else
            tus = New sync_thread_unsafe_lazier(Of T)(d)
        End If
    End Sub

    Public Sub New(ByVal v As T)
        If threadsafe Then
            ts = New sync_thread_safe_lazier(Of T)(v)
        Else
            tus = New sync_thread_unsafe_lazier(Of T)(v)
        End If
    End Sub

    Public Function alive() As Boolean
        If threadsafe Then
            assert(Not ts Is Nothing)
            Return ts.alive()
        Else
            assert(Not tus Is Nothing)
            Return tus.alive()
        End If
    End Function

    Public Function [get]() As T
        If threadsafe Then
            assert(Not ts Is Nothing)
            Return ts.get()
        Else
            assert(Not tus Is Nothing)
            Return tus.get()
        End If
    End Function
End Class

Public Class sync_thread_unsafe_lazier(Of T)
    Private ReadOnly d As Func(Of T)
    Private initialized As Boolean
    Private v As T

    Private Sub New(ByVal initialized As Boolean)
        Me.initialized = initialized
        Me.d = Nothing
        Me.v = Nothing
    End Sub

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(ByVal d As Func(Of T))
        Me.New(False)
        assert(Not d Is Nothing)
        Me.d = d
    End Sub

    Public Sub New(ByVal v As T)
        Me.New(True)
        assert(Not v Is Nothing)
        Me.v = v
    End Sub

    Protected Overridable Function prepare() As T
        assert(Not d Is Nothing)
        Return d()
    End Function

    Public Function alive() As Boolean
        Return initialized
    End Function

    Public Function [get]() As T
        If Not initialized Then
            assert(v Is Nothing OrElse is_valuetype(Of T)())
            Try
                v = prepare()
            Catch ex As Exception
                assert(False, ex)
            End Try
            initialized = True
        End If
        Return v
    End Function
End Class

Public Class sync_thread_safe_lazier(Of T)
    Private ReadOnly finish_get As ManualResetEvent
    Private ReadOnly d As Func(Of T)
    Private initialized As Boolean
    Private begin_get As singleentry
    Private v As T

    Private Sub New(ByVal initialized As Boolean)
        Me.initialized = initialized
        If initialized Then
            Me.finish_get = Nothing
        Else
            Me.finish_get = New ManualResetEvent(False)
        End If
        Me.v = Nothing
        Me.d = Nothing
    End Sub

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(ByVal d As Func(Of T))
        Me.New(False)
        assert(Not d Is Nothing)
        Me.d = d
    End Sub

    Public Sub New(ByVal v As T)
        Me.New(True)
        assert(Not v Is Nothing)
        Me.v = v
    End Sub

    Protected Overridable Function prepare() As T
        assert(Not d Is Nothing)
        Return d()
    End Function

    Public Function alive() As Boolean
        Return initialized
    End Function

    Public Function [get]() As T
        If Not initialized Then
            assert(Not finish_get Is Nothing)
            If begin_get.mark_in_use() Then
                assert(v Is Nothing OrElse is_valuetype(Of T)())
                Try
                    v = prepare()
                Catch ex As Exception
                    assert(False, ex)
                End Try
                assert(finish_get.Set())
                initialized = True
            Else
                assert(finish_get.WaitOne())
            End If
        End If
        Return v
    End Function

    Protected Overrides Sub Finalize()
        If Not finish_get Is Nothing Then
            finish_get.Close()
            GC.KeepAlive(finish_get)
        End If
        MyBase.Finalize()
    End Sub
End Class
